import BaseChart from '../../BaseChart.js'
export default class sankey extends BaseChart {
	constructor(id, data) {
		super(id, data)

		this.from = 'from'
		this.to = 'to'

		this.filterData = null
		this.standardData = null

		this.nodes = []
		this.links = []
		this.nodesGroup = null
		this.linksGroup = null
		this.textGroup = null
		this.gradient = null
		this.nodesGroupElements = null
		this.linksGroupElements = null
		this.textGroupElements = null

		this.color = null
		this.sankey = null
	}
	setFrom(from) {
		this.from = from
		return this
	}
	setTo(to) {
		this.to = to
		return this
	}
	/**
	 * 初始化svg画布、mg、桑基图生成器、颜色比例尺、group、以及颜色渐变
	 */
	init() {
		this.initSvg() //初始化Svg画布
		this.initMainGroup() //初始化主题内容部分
		this.initSankey() //生成器
		this.initScale() //比例尺
		this.initGroups()
		this.initZoom()
		return this
	}


	initZoom() {
		this.svg
			.call(d3.zoom()
				.on('zoom', this.zoomed)
			)
	}

	initGroups() {
		this.nodesGroup = this.mg
			.append('g')
			.attr('id', `${this.id}nodesGroup`)
		this.linksGroup = this.mg
			.append('g')
			.attr('id', `${this.id}linksGroup`)
			.attr('fill', 'none')
			.attr('stroke-opacity', 0.5)
		this.textGroup = this.mg
			.append('g')
			.attr('id', `${this.id}textGroup`)
	}

	initSankey() {
		this.sankey = d3.sankey()
			.nodeId(d => d['name'])
			.nodeWidth(15)
			.nodePadding(10)
			.extent([
				[0, 0],
				[this.innerWidth, this.innerHeight],
			])
	}

	initScale() {
		this.color = d3
			.scaleOrdinal()
			.domain(this.data.map((d) => d['name']))
			.range(d3.schemeCategory10)
	}

	render(data) {
		if(data){
			this.data = data;
		}
		this.renderData()
		this.renderNodes()
		this.renderLinks()
		this.renderTexts()
		return this;
	}

	renderData() {
		this.links = JSON.parse(JSON.stringify(this.data));
		
		this.nodes = Array.from(
			new Set(this.links.flatMap(l => [l.source, l.target])), name => ({ name, category: name.replace(/ .*/, "") }))
			this.links.forEach(d => {
			d['value'] = + d['value']
			d['index'] = + d['index']
		})

		let { nodes, links } = this.sankey({
			nodes: this.nodes.map(d => Object.assign({}, d)),
			links: this.links.map(d => Object.assign({}, d))
		})

		this.nodes = nodes;
		this.links = links;
	}

	renderNodes() {
		this.nodesGroupElements = this.nodesGroup
			.attr('stroke', '#000')
			.selectAll('rect')
			.data(this.nodes)
			.join('rect');
		this.nodesGroupElements
			.attr('x', (d) => d.x0)
			.attr('y', (d) => d.y0)
			.attr('height', (d) => d.y1 - d.y0)
			.attr('width', (d) => d.x1 - d.x0)
			.attr('fill', (d) => this.color(d.name))
	}

	renderLinks() {
		this.linksGroupElements = this.linksGroup
			.selectAll('g')
			.data(this.links)
			.join('g')
			.style('mix-blend-mode', 'multiply')
		this.renderGradient();
		this.linksGroupElements
			.selectAll("path")
			.data(d=>[d])
			.join("path")
			
			.attr('d', d3.sankeyLinkHorizontal())
			.attr('stroke', d =>`url(#${d.id})`)
			.attr('stroke-width', (d) => d.width)
			.style('mix-blend-mode', 'multiply')
	}

	renderGradient() {
		this.gradient = this.linksGroupElements
			.selectAll("linearGradient")
			.data(d => [d])
			.join("linearGradient")
			.attr("id", d => d.id =  Math.random())
			.attr("gradientUnits", "userSpaceOnUse")

		this.gradient
			.selectAll('stop')	
			.data( d => [{
				offset:"0%",
				category : d.source.category
			},{
				offset:"100%",
				category : d.target.category
			}])
			.join('stop')
			.attr("offset", d=>d.offset)
			.attr("stop-color",d=> this.color(d.category))
	}

	renderTexts() {
		this.textGroupElements = this.textGroup
			.attr('font-family', 'sans-serif') //字体种类
			.attr('font-size', 10) //字体大小
			.selectAll('text')
			.data(this.nodes)
			.join('text')
			.attr('x', (d) => (d.x0 < this.innerWidth / 2 ? d.x1 + 6 : d.x0 - 6))
			.attr('y', (d) => (d.y1 + d.y0) / 2)
			.attr('dy', '0.35em')
			.attr('text-anchor', (d) => (d.x0 < this.innerWidth / 2 ? 'start' : 'end'))
			.text((d) => d.name)
	}
	zoomed = (event) => {
		this.mg.attr('transform', `translate(${event.transform.x},${event.transform.y}) scale(${event.transform.k})`)
	}
}
